﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using My.Pattern.Factory;
using My.Web.MVC.V4.Factory;
using NCLCustomerManagement.BusinessLogic.Category;
using NCLCustomerManagement.DataTransferObjects.Customer;
using NCLCustomerManagement.UI.Helper;
using NCLCustomerManagement.UI.Helper.Extensions;
using NCLCustomerManagement.UI.Helper.Utils;
using My.Common.Helper.JqGrid;
using NCLCustomerManagement.UI.Models.Customer;
using NCLCustomerManagement.UI.Models.ProductCategory;
using NCLCustomerManagement.BusinessLogic.User;
using NCLCustomerManagement.UI.Models.User;
using NCLCustomerManagement.DataTransferObjects.User;
using System.Text;
using NCLCustomerManagement.Common.Exception;

namespace NCLCustomerManagement.UI.Controllers
{
    public class HomeController : BaseController
    {
        private ICustomerBC _custBC;
        private IUserRequestBC _requestBC;
        private IBuildGridDataHelper<CustomerModel> _buildGridDataHelper;

        public HomeController(IBCFactory bcFactory, IBuildGridDataHelper<CustomerModel> buildGridDataHelper)
        {

            _custBC = bcFactory.GetBC<ICustomerBC>();
            _requestBC = bcFactory.GetBC<IUserRequestBC>();
            //_sessionFactory = new SessionDataFactory(this);
            _buildGridDataHelper = buildGridDataHelper;

        }

        [HttpGet]
        [AuthenticationRequired]
        public ActionResult Index()
        {
            this.SetupCategoryListForDropdown(_custBC);
            GetUnviewedMessageCount();
            return View();
        }

        [AuthenticationRequired]
        [HttpGet]
        public ActionResult SelectCustomer()
        {
            this.SetupCategoryListForDropdown(_custBC);
            GetUnviewedMessageCount();
            return PartialView("_SelectCustomerPartial");
        }
        [AuthenticationRequired]
        public ActionResult New()
        {
            this.SetupCategoryListForAllItemsListBox(_custBC);
            ViewBag.RegionList = this.SetupRegion();
            return PartialView();
        }

        [AuthenticationRequired]
        public JsonResult SubmitNew(string customer)
        {
            bool ok = true;
            var customerModel = JsSerializer.Deserialize<CustomerModel>(customer);
            var currentUser = this.GetCurrentUser();
            if (currentUser.IsAdmin)
            {
                customerModel.LastModifiedDate = DateTime.Now;
                customerModel.LastModifiedUser = currentUser.Username;
            }
            var dto = ConvertCustomerModelToDTO(customerModel);
            try
            {
                _custBC.AddNewCustomer(dto);
                AddToHistory(string.Format("Thêm khách hàng {0}, ĐT {1}", dto.CustomerName, dto.Phone));
            }
            catch
            {
                ok = false;
            }

            return Json(new { Success = ok }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public ActionResult Edit(int id)
        {
            this.SetupCategoryListForAllItemsListBox(_custBC);
            var dto = _custBC.GetCustomerById(id);
            var model = ConvertCustomerDTOToModel(dto);
            ViewBag.RegionList = this.SetupRegion(model.CustomerRegion);
            return PartialView(model);
        }

        [AuthenticationRequired]
        public JsonResult SubmitEdit(string customer)
        {
            bool ok = true;
            var currentUser = this.GetCurrentUser();
            var customerModel = JsSerializer.Deserialize<CustomerModel>(customer);
            customerModel.LastModifiedDate = DateTime.Now;
            customerModel.LastModifiedUser = currentUser.Username;

            var dto = ConvertCustomerModelToDTO(customerModel);
            try
            {
                var oldCustomer = ConvertCustomerDTOToModel(_custBC.GetCustomerById(dto.Id));

                _custBC.UpdateCustomer(dto);

                var diff = GetDifference(oldCustomer, customerModel);
                AddToHistory(string.Format("Cập nhật khách hàng  {0}, ĐT {1} (cũ): {2} ",
                    oldCustomer.CustomerName,
                    oldCustomer.Phone,
                    diff));
            }
            catch
            {
                ok = false;
            }
            return Json(new { Success = ok }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult RequestChange(string customer)
        {
            bool ok = true;
            string msg = "";
            var customerModel = JsSerializer.Deserialize<CustomerModel>(customer);
            var dto = ConvertCustomerModelToDTO(customerModel);

            bool hasChange = _custBC.CheckChange(dto);
            if (hasChange)
            {
                var currentUser = this.GetCurrentUser();
                try
                {
                    _custBC.RequestChange(dto, currentUser.Username, currentUser.Manager);
                    msg = "Yêu cầu của bạn đã được gửi và đang chờ quản lý của bạn phê duyệt";

                    var oldCustomer = ConvertCustomerDTOToModel(_custBC.GetCustomerById(dto.Id));
                    var diff = GetDifference(oldCustomer, customerModel);
                    AddToHistory(string.Format("{0} gửi yêu cầu cập nhật khách hàng {1}, ĐT {2} (cũ): {3}",
                        currentUser.Username,
                        oldCustomer.CustomerName,
                        oldCustomer.Phone,
                        diff));
                }
                catch
                {
                    msg = "Rất tiếc. Không thể xử lý yêu cầu của bạn lúc này";
                    ok = false;
                }
            }
            else
            {
                msg = "Không nhận thấy có thay đổi nào cả";
                ok = false;
            }
            return Json(new { Success = ok, Message = msg }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult Delete(int[] deletedIds)
        {
            bool ok = true;

            try
            {
                var deletedCustomers = deletedIds.Select(e => _custBC.GetCustomerById(e)).ToList();
                _custBC.DeleteCustomer(deletedIds);
                foreach (var item in deletedCustomers)
                {
                    AddToHistory(string.Format("Xóa khách hàng {0}, ĐT {1}", item.CustomerName, item.Phone));
                }
            }
            catch
            {
                ok = false;
            }
            return Json(new { Success = ok }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public string GetCustomerList(int? regionId, int? productCategoryId, string phone, bool isAdmin,
            string sortName = "Name",
            string sortOrder = "asc", int rowId = -1)
        {

            if (regionId == -1)
                regionId = null;
            if (productCategoryId == -1)
                productCategoryId = null;

            var customers = _custBC.GetCustomerList(regionId, productCategoryId, phone, isAdmin)
                .Select(e => ConvertCustomerDTOToModel(e))
                .OrderBy(e => e.LastModifiedDate)
                .Reverse()
                .ToList();
            return _buildGridDataHelper.BuildDataForGrid(customers, this.CreateRowsJson, sortName, sortOrder, rowId);
        }

        [AuthenticationRequired]
        public ActionResult SearchCategory(string name)
        {
            var allCates = this.GetAllCategories(_custBC)
                .Where(e => e.ProductCategoryName.ToLower().Contains(name.ToLower()))
                .ToList();
            var model = new SelectList(allCates, "Id", "ProductCategoryName");
            return PartialView("_FoundCategories", model as object);
        }

        [AuthenticationRequired]
        public JsonResult CheckPhoneExist(string customer)
        {
            var model = JsSerializer.Deserialize<CustomerModel>(customer);
            var custList = _custBC.GetCustomerList(null, null, model.Phone, false)
                .Where(e => e.Id != model.Id)
                .ToList();
            return Json(new { Exist = custList.Count > 0 }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult CheckProductOfCustomerExist(int productId, int customerId)
        {
            var exist = _custBC.CheckProductExist(productId, customerId);
            return Json(new { Exist = exist }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public ActionResult MessageBoard()
        {
            var currentUser = this.GetCurrentUser();
            IEnumerable<UserRequestModel> requests;

            if (!currentUser.IsAdmin)
            {
                requests = _requestBC.GetApprovedOrRejectedSentRequests(currentUser.Username)
                    .Select(e => ConvertUserRequestDTOToModel(e))
                    .OrderBy(e => e.RequestedDate)
                    .Reverse()
                    .ToList();
            }
            else
            {
                requests = _requestBC.GetReceivedRequests(currentUser.Username)
                     .Select(e => ConvertUserRequestDTOToModel(e))
                     .OrderBy(e => e.RequestedDate)
                     .Reverse()
                     .ToList();
            }
            return View("_MessageBoard", requests as object);
        }

        [AuthenticationRequired]
        public JsonResult SetMessageAsViewed(int id)
        {
            _requestBC.UpdateRequestAsViewed(id);
            return Json("", JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult GetUnviewedMessageCount()
        {
            var user = this.GetCurrentUser();
            int count = _requestBC.GetUnviewedMessageCount(user.Username, user.IsAdmin);
            ViewBag.UnviewedMessageCount = count;
            return Json(count, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult DeleteRequest(int id)
        {

            _requestBC.DeleteRequest(id);
            return Json("", JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult ApproveRequest(int id)
        {
            var user = this.GetCurrentUser();
            if (user.IsAdmin)
            {
                _requestBC.ApproveOrRejectRequest(id, true);
                var request = _requestBC.GetRequest(id);
                AddToHistory(string.Format("{0} phê duyệt yêu cầu được gửi bởi {1} vào {2:dd/MM/yyyy}",
                    user.Username,
                    request.Requester,
                    request.RequestedDate));
            }
            return Json("", JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult RejectRequest(int id)
        {
            var user = this.GetCurrentUser();
            if (user.IsAdmin)
            {
                _requestBC.ApproveOrRejectRequest(id, false);
                var request = _requestBC.GetRequest(id);
                AddToHistory(string.Format("{0} từ chối yêu cầu được gửi bởi {1} vào {2:dd/MM/yyyy}",
                    user.Username,
                    request.Requester,
                    request.RequestedDate));
            }
            return Json("", JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult ApplyChange(int id)
        {
            bool ok = true;
            string msg = "";
            try
            {
                var currentUser = this.GetCurrentUser();
                var request = _requestBC.GetRequest(id);

                request.NewCustomer.LastModifiedDate = DateTime.Now;
                request.NewCustomer.LastModifiedUser = currentUser.Username;

                var oldCustomer = ConvertCustomerDTOToModel(_custBC.GetCustomerById(request.CurrentCustomer.Id));

                _custBC.UpdateCustomer(request.NewCustomer);
               
                var diff = GetDifference(oldCustomer, ConvertCustomerDTOToModel(request.NewCustomer));
                AddToHistory(string.Format("Cập nhật khách hàng  {0}, ĐT {1} (cũ): {2} ",
                    oldCustomer.CustomerName,
                    oldCustomer.Phone,
                    diff));

                _requestBC.DeleteRequest(id);
                msg = "Đã áp dụng thay đổi";

            }
            catch (EntityNotFoundException)
            {
                ok = false;
                msg = "Không thể áp dụng thay đổi do khách hàng không tồn tại";
            }
            catch (Exception)
            {
                ok = false;
                msg = "Không thể áp dụng thay đổi";
            }
            return Json(new { Success = ok, Message = msg }, JsonRequestBehavior.AllowGet);
        }


        [AuthenticationRequired]
        public ActionResult ProductCategory()
        {
            var model = _custBC.GetAllCategories().Select(e => ConvertDTOToModel<ProductCategoryDTO, ProductCategoryModel>(e));
            return View(model);
        }

        [AuthenticationRequired]
        public ActionResult GetCategoryListPartial()
        {
            var model = _custBC.GetAllCategories().Select(e => ConvertDTOToModel<ProductCategoryDTO, ProductCategoryModel>(e));
            return PartialView("_CategoryListPartial", model);
        }

        [AuthenticationRequired]
        public JsonResult SubmitNewCategory(string id)
        {
            bool ok = true;
            string msg = "";
            if (string.IsNullOrEmpty(id))
            {
                return Json(new { Success = false, Message = "Bạn chưa nhập nhóm sản phẩm" }, JsonRequestBehavior.AllowGet);
            }
            if (_custBC.GetAllCategories().Any(e => e.ProductCategoryName == id))
            {
                return Json(new { Success = false, Message = "Bạn hãy chọn tên khác" }, JsonRequestBehavior.AllowGet);
            }

            try
            {
                _custBC.AddNewProductCategory(id);
                msg = "Đã thêm nhóm sản phẩm";
                AddToHistory(string.Format("Thêm nhóm sản phẩm {0}", id));
            }
            catch (Exception)
            {
                ok = false;
                msg = "Gặp sự cố khi thêm mới nhóm sản phẩm. Bạn hãy thử lại sau";
            }
            return Json(new { Success = ok, Message = msg }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult SubmitDeleteCategory(int[] ids)
        {
            bool ok = true;
            string msg = "";
            try
            {
                var allCategories = _custBC.GetAllCategories();
                var deletedCates = ids.Select(e => allCategories.SingleOrDefault(f => f.Id == e))
                    .ToList();

                _custBC.DeleteCategory(ids);
                msg = "Đã xóa nhóm sản phẩm";

                foreach (var item in deletedCates)
                    AddToHistory(string.Format("Xóa nhóm sản phẩm {0}", item.ProductCategoryName));
            }
            catch (Exception)
            {
                ok = false;
                msg = "Gặp sự cố khi xóa nhóm sản phẩm";
            }
            return Json(new { Success = ok, Message = msg }, JsonRequestBehavior.AllowGet);
        }

        [AuthenticationRequired]
        public JsonResult SubmitUpdateCategory(int id, string name)
        {
            bool ok = true;
            string msg = "";
            if (string.IsNullOrEmpty(name))
            {
                return Json(new { Success = false, Message = "Nhóm sản phẩm không thể trống" }, JsonRequestBehavior.AllowGet);
            }
            if (_custBC.GetAllCategories().Any(e => e.ProductCategoryName == name))
            {
                return Json(new { Success = false, Message = "Bạn hãy chọn tên khác" }, JsonRequestBehavior.AllowGet);
            }

            try
            {
                var oldCate = _custBC.GetAllCategories().SingleOrDefault(e => e.Id == id);
                _custBC.UpdateProductCategory(id, name);
                msg = "Đã cập nhật nhóm sản phẩm";
                AddToHistory(string.Format("Cập nhật nhóm sản phẩm {0} thành {1}", oldCate.ProductCategoryName, name));
            }
            catch (Exception)
            {
                ok = false;
                msg = "Gặp sự cố khi cập nhật nhóm sản phẩm. Bạn hãy thử lại sau";
            }
            return Json(new { Success = ok, Message = msg }, JsonRequestBehavior.AllowGet);
        }

        private CustomerModel ConvertCustomerDTOToModel(CustomerDTO dto)
        {
            return new CustomerModel()
            {
                Id = dto.Id,
                Address = dto.Address,
                Bank = dto.Bank,
                CreditCardNumber = dto.CreditCardNumber,
                CustomerName = dto.CustomerName,
                CustomerRegion = dto.CustomerRegion,
                LastModifiedDate = dto.LastModifiedDate,
                LastModifiedUser = dto.LastModifiedUser,
                Phone = dto.Phone,
                Notes = dto.Notes,
                Products = dto.Products.Select(e => AutoMapperBuilder.MapSourceToDestination<ProductCategoryDTO, ProductCategoryModel>(e)).ToList()
            };

        }

        private CustomerDTO ConvertCustomerModelToDTO(CustomerModel model)
        {
            return new CustomerDTO()
            {
                Id = model.Id,
                Address = model.Address,
                Bank = model.Bank,
                CreditCardNumber = model.CreditCardNumber,
                CustomerName = model.CustomerName,
                CustomerRegion = model.CustomerRegion,
                LastModifiedDate = model.LastModifiedDate,
                LastModifiedUser = model.LastModifiedUser,
                Phone = model.Phone,
                Notes = model.Notes,
                Products = model.Products.Select(e => AutoMapperBuilder.MapSourceToDestination<ProductCategoryModel, ProductCategoryDTO>(e)).ToList()
            };

        }

        private UserRequestModel ConvertUserRequestDTOToModel(UserRequestDTO dto)
        {
            var model = new UserRequestModel()
            {
                Id = dto.Id,
                RequestedDate = dto.RequestedDate,
                Requester = dto.Requester,
                RequestTo = dto.RequestTo,
                Status = dto.Status,
                Viewed = dto.Viewed,
                ApproveRejectDate = dto.ApproveRejectDate,
            };
            model.CurrentCustomer = ConvertCustomerDTOToModel(dto.CurrentCustomer);
            model.NewCustomer = ConvertCustomerDTOToModel(dto.NewCustomer);
            model.RequestContent = GetDifference(model.CurrentCustomer, model.NewCustomer);
            return model;
        }

        private string GetDifference(CustomerModel current, CustomerModel other)
        {
            StringBuilder builder = new StringBuilder();
            if (current.CustomerName != other.CustomerName)
            {
                builder.AppendFormat("<div>Họ tên: Từ <b>{0}</b> thành <b>{1}</b></div>", current.CustomerName, other.CustomerName);
            }

            if (current.Address != other.Address)
            {
                builder.AppendFormat("<div>Địa chỉ: Từ <b>{0}</b> thành <b>{1}</b></div>", current.Address, other.Address);
            }
            if (current.CustomerRegion != other.CustomerRegion)
            {
                builder.AppendFormat("<div>Miền: Từ <b>{0}</b> thành <b>{1}</b></div>",
                    RegionToString(current.CustomerRegion),
                    RegionToString(other.CustomerRegion));
            }
            if (current.Phone != other.Phone)
            {
                builder.AppendFormat("<div>Điện thoại: Từ <b>{0}</b> thành <b>{1}</b></div>", current.Phone, other.Phone);
            }
            if (current.Notes != other.Notes)
            {
                builder.AppendFormat("<div>Ghi chú: Từ <b>{0}</b> thành <b>{1}</b></div>",current.Notes, other.Notes);
            }

            var addedProducts = other.Products
                .Select(e => e.Id)
                .Except(current.Products.Select(e => e.Id))
                .ToList();
            if (addedProducts.Count > 0)
            {
                builder.AppendFormat("<div>Mới thêm các nhóm sản phẩm: {0}</div>",
                    string.Join(", ", addedProducts.Select(e => new ProductCategoryModel()
                    {
                        Id = e,
                        ProductCategoryName = _custBC.GetAllCategories()
                            .ToList()
                            .SingleOrDefault(f => f.Id == e) != null ? _custBC.GetAllCategories()
                            .ToList()
                            .SingleOrDefault(f => f.Id == e)
                            .ProductCategoryName : "Đã bị xóa"
                    })
                    .Select(e => e.ProductCategoryName)));
            }

            var removedProducts = current.Products.Select(e => e.Id)
                .Except(other.Products.Select(e => e.Id))
                .ToList();

            if (removedProducts.Count > 0)
            {
                builder.AppendFormat("<div>Mới xóa các nhóm sản phẩm: {0}</div>",
                    string.Join(", ", removedProducts.Select(e => new ProductCategoryModel()
                    {
                        Id = e,
                        ProductCategoryName = _custBC.GetAllCategories()
                            .ToList()
                            .SingleOrDefault(f => f.Id == e) != null ? _custBC.GetAllCategories()
                            .ToList()
                            .SingleOrDefault(f => f.Id == e)
                            .ProductCategoryName : "Đã bị xóa"
                    })
                    .Select(e => e.ProductCategoryName)));
            }


            return builder.ToString();
        }

        private string RegionToString(Region region)
        {
            switch (region)
            {
                case Region.North: return "Bắc";
                case Region.Middle: return "Trung";
                case Region.South: return "Nam";
                default: return "";
            }
        }
    }
}
